#include "commons.h"
#include <stdio.h>
#include <string.h>
#include "allegro.h"
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void log_trace( BYTE opcode ) {
    char log[ 300 ];
    
    sprintf( log, "%04X  %02X ", emu->m6502->pc.w - 1, opcode );
    
    switch( opcode ) {
        case 0x11:
        case 0x31:
        case 0x51:
        case 0x71:
        case 0x91:
        case 0xb1:
        case 0xd1:
        case 0xf1:
            sprintf( log,
                     "%s%02X     %s ($%02X),Y = %04X @ %04X = %02X  ",
                     log, fetch_operand(1), solve_opcode_name(opcode), fetch_operand(1),
                     read_memory(read_memory(emu->m6502->pc.w)) | (read_memory((BYTE)(read_memory(emu->m6502->pc.w) + 1)) << 8),
                     (WORD)((read_memory(read_memory(emu->m6502->pc.w)) | (read_memory((BYTE)(read_memory(emu->m6502->pc.w) + 1)) << 8)) + emu->m6502->y),
                     read_memory((WORD)((read_memory(read_memory(emu->m6502->pc.w)) | (read_memory((BYTE)(read_memory(emu->m6502->pc.w) + 1)) << 8)) + emu->m6502->y)) );
            break;
        case 0x01:
        case 0x21:
        case 0x41:
        case 0x61:
        case 0x81:
        case 0xa1:
        case 0xc1:
        case 0xe1:
            sprintf( log,
                     "%s%02X     %s ($%02X,X) @ %02X = %02X%02X = %02X    ",
                     log, fetch_operand(1), solve_opcode_name(opcode), fetch_operand(1), (BYTE)(fetch_operand(1) + emu->m6502->x),
                     read_memory((BYTE)(fetch_operand(1) + emu->m6502->x + 1)), read_memory((BYTE)(fetch_operand(1) + emu->m6502->x)),
                     read_memory((WORD)((read_memory((BYTE)(fetch_operand(1) + emu->m6502->x + 1)) << 8) | read_memory((BYTE)(fetch_operand(1) + emu->m6502->x)))) );
            break;
        case 0x6c:
            sprintf( log,
                     "%s%02X %02X  %s ($%02X%02X) = %04X              ",
                     log, fetch_operand(1), fetch_operand(2), solve_opcode_name(opcode), fetch_operand(2), fetch_operand(1),
                     (read_memory((WORD)((read_memory((WORD)(emu->m6502->pc.w + 1)) << 8) | (read_memory(emu->m6502->pc.w) + 1))) << 8) | read_memory((read_memory((WORD)(emu->m6502->pc.w + 1)) << 8) | read_memory(emu->m6502->pc.w)) );
            break;
        case 0x0a:
        case 0x2a:
        case 0x4a:
        case 0x6a:
            sprintf( log,
                     "%s       %s A                           ",
                     log, solve_opcode_name(opcode) );
            break;
        case 0x20:
        case 0x4c:
            sprintf( log,
                     "%s%02X %02X  %s $%02X%02X                       ",
                     log, fetch_operand(1), fetch_operand(2), solve_opcode_name(opcode), fetch_operand(2), fetch_operand(1) );
            break;
        case 0x05:
        case 0x06:
        case 0x24:
        case 0x25:
        case 0x26:
        case 0x45:
        case 0x46:
        case 0x65:
        case 0x66:
        case 0x84:
        case 0x85:
        case 0x86:
        case 0xa4:
        case 0xa5:
        case 0xa6:
        case 0xc4:
        case 0xc5:
        case 0xc6:
        case 0xe4:
        case 0xe5:
        case 0xe6:
            sprintf( log,
                     "%s%02X     %s $%02X = %02X                    ",
                     log, fetch_operand(1), solve_opcode_name(opcode), fetch_operand(1), read_memory(fetch_operand(1)) );
            break;
        case 0x15:
        case 0x16:
        case 0x35:
        case 0x36:
        case 0x55:
        case 0x56:
        case 0x75:
        case 0x76:
        case 0x94:
        case 0x95:
        case 0xb4:
        case 0xb5:
        case 0xd5:
        case 0xd6:
        case 0xf5:
        case 0xf6:
            sprintf( log,
                     "%s%02X     %s $%02X,X @ %02X = %02X             ",
                     log, fetch_operand(1), solve_opcode_name(opcode), fetch_operand(1),
                     (BYTE)(fetch_operand(1) + emu->m6502->x), read_memory((BYTE)(fetch_operand(1) + emu->m6502->x)) );
            break;
        case 0x96:
        case 0xb6:
            sprintf( log,
                     "%s%02X     %s $%02X,Y @ %02X = %02X             ",
                     log, fetch_operand(1), solve_opcode_name(opcode), fetch_operand(1),
                     (BYTE)(fetch_operand(1) + emu->m6502->y), read_memory((BYTE)(fetch_operand(1) + emu->m6502->y)) );
            break;
        case 0x0d:
        case 0x0e:
        case 0x2c:
        case 0x2d:
        case 0x2e:
        case 0x4d:
        case 0x4e:
        case 0x6d:
        case 0x6e:
        case 0x8c:
        case 0x8d:
        case 0x8e:
        case 0xae:
        case 0xac:
        case 0xad:
        case 0xcc:
        case 0xcd:
        case 0xce:
        case 0xec:
        case 0xed:
        case 0xee:
            sprintf( log,
                     "%s%02X %02X  %s $%02X%02X = %02X                  ",
                     log, fetch_operand(1), fetch_operand(2), solve_opcode_name(opcode), fetch_operand(2), fetch_operand(1), read_memory(fetch_operand(1) | (fetch_operand(2) << 8)) );
            break;
        case 0x19:
        case 0x39:
        case 0x59:
        case 0x79:
        case 0x99:
        case 0xb9:
        case 0xbe:
        case 0xd9:
        case 0xf9:
            sprintf( log,
                     "%s%02X %02X  %s $%02X%02X,Y @ %04X = %02X         ",
                     log, fetch_operand(1), fetch_operand(2), solve_opcode_name(opcode), fetch_operand(2), fetch_operand(1),
                     (WORD)(((fetch_operand(2) << 8) | fetch_operand(1)) + emu->m6502->y),
                     read_memory((WORD)(((fetch_operand(2) << 8) | fetch_operand(1)) + emu->m6502->y)) );
            break;
        case 0x1e:
        case 0x1d:
        case 0x3d:
        case 0x3e:
        case 0x5d:
        case 0x5e:
        case 0x7d:
        case 0x7e:
        case 0x9d:
        case 0xbc:
        case 0xbd:
        case 0xdd:
        case 0xde:
        case 0xfd:
        case 0xfe:
            sprintf( log,
                     "%s%02X %02X  %s $%02X%02X,X @ %04X = %02X         ",
                     log, fetch_operand(1), fetch_operand(2), solve_opcode_name(opcode), fetch_operand(2), fetch_operand(1),
                     (WORD)(((fetch_operand(2) << 8) | fetch_operand(1)) + emu->m6502->x),
                     read_memory((WORD)(((fetch_operand(2) << 8) | fetch_operand(1)) + emu->m6502->x)) );
            break;
        case 0x09:
        case 0x29:
        case 0x49:
        case 0x69:
        case 0xa0:
        case 0xa2:
        case 0xa9:
        case 0xc0:
        case 0xc9:
        case 0xe0:
        case 0xe9:
            sprintf( log,
                     "%s%02X     %s #$%02X                        ",
                     log, fetch_operand(1), solve_opcode_name(opcode), fetch_operand(1) );
            break;
        case 0x10:
        case 0x30:
        case 0x50:
        case 0x70:
        case 0x90:
        case 0xb0:
        case 0xd0:
        case 0xf0:
            sprintf( log,
                     "%s%02X     %s $%04X                       ",
                     log, fetch_operand(1), solve_opcode_name(opcode), (WORD)(emu->m6502->pc.w + 1 + fetch_operand(1)) );
            break;
        case 0x08:
        case 0x18:
        case 0x28:
        case 0x38:
        case 0x40:
        case 0x48:
        case 0x60:
        case 0x68:
        case 0x78:
        case 0x88:
        case 0x8a:
        case 0x98:
        case 0x9a:
        case 0xa8:
        case 0xaa:
        case 0xba:
        case 0xb8:
        case 0xc8:
        case 0xca:
        case 0xd8:
        case 0xea:
        case 0xe8:
        case 0xf8:
            sprintf( log,
                     "%s       %s                             ",
                     log, solve_opcode_name(opcode) );
            break;
    }
    
    sprintf( log,
             "%sA:%02X X:%02X Y:%02X P:%02X SP:%02X CYC:%3i\n",
             log, emu->m6502->a, emu->m6502->x, emu->m6502->y, emu->m6502->status, emu->m6502->sp, emu->m6502->ticks );
    printf( "%s", log );
    
    // FIXME: dump del log en un archivo
    /*FILE* fp = fopen( "C:\\Users\\Luqui\\Desktop\\jane\\_temp\\log.txt", "at" );
    fputs( log, fp );
    fclose( fp );*/
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
BYTE fetch_operand( int operand ) {
    return read_memory( emu->m6502->pc.w + operand - 1 );
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
char* solve_opcode_name( BYTE opcode ) {
    static char name[4];
    
    memcpy( name, OPCODE_NAME[opcode], 3 );
    name[3] = '\0';
    
    return name;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void dump_memory( BYTE* memory, int block_size ) {
    int i = 0;
    char log_string[100];

    printf( "Generando dump...\n" );
    FILE* fp = fopen( "C:\\Users\\Luqui\\Desktop\\jane\\_temp\\dump.txt", "wt" );
    while( i < block_size ) {
        sprintf( log_string, "%04X: %02X\n", i, memory[i] );
        fputs( log_string, fp );
        i++;
    }
    fclose( fp );
    printf( "Dump completo...\n" );
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void trace_pattern_tables() {
    int x = 0, y = 0, t = 0, i = 0;
    long buffer[ 240 ][ 256 ];

    for( t = 0; t < 0x1000; t += 0x10 ) {
        if( (t > 0) && (t % 256 == 0) ) {
            x = 0;
            y += 8;
        }
        int temp_x = x, temp_y = y;
        for( i = 0; i < 8; i++ ) {
            BYTE pattern_table_entry_l = emu->vram[ i + t ];
            BYTE pattern_table_entry_h = emu->vram[ i + t + 8 ];
            int k = 7, j = 0;
            for( j = 0; j < 8; j++, k--, temp_x++ ) {
                BYTE color_bit_0 = ( (pattern_table_entry_l >> k) & 0x1 );
                BYTE color_bit_1 = ( (pattern_table_entry_h >> k) & 0x1 );
                BYTE color_index = ( (color_bit_1 << 1) | color_bit_0 );
                BYTE pallete_entry = emu->vram[ 0x3f00 + color_index ];
                buffer[ temp_y ][ temp_x ] = COLOR_PALLETE[ pallete_entry ];
            }
            temp_x = x;
            temp_y++;
        }
        x += 8;
    }
    
    BITMAP* bmp = create_bitmap( 256, 240 );
    //lock_bitmap( bmp );
    int cx = 0, cy = 0;
    for( cx = 0; cx < 256; cx++ ) {
        for( cy = 0; cy < 240; cy++ ) {
            int r = ( (buffer[cy][cx] & 0xff0000) >> 16 );
            int g = ( (buffer[cy][cx] & 0x00ff00) >> 8 );
            int b = ( (buffer[cy][cx] & 0x0000ff) >> 0 );
            putpixel( bmp, cx, cy, makecol_depth(16, r, g, b) );
            //printf("X:%3i Y:%3i COLOR:%X\n", cx, cy, buffer[cy][cx]);
        }
    }
    blit( bmp, screen, 0, 0, 0, 0, 256, 240 );
    //dump_memory( emu->vram, 0x1000 );

    /*ALLEGRO_BITMAP *bmp = al_get_backbuffer(PatternTablesViewer);
    ALLEGRO_LOCKED_REGION *lock;
    al_set_target_bitmap(bmp);
    lock = al_lock_bitmap(bmp, ALLEGRO_PIXEL_FORMAT_ARGB_8888, ALLEGRO_LOCK_WRITEONLY);
    uint8_t *data = (uint8_t *)lock->data;
    int row_size = 520*4;
    if (row_size < 0) row_size = -row_size;
    for (int y = 0; y < 256; y++, data += lock->pitch) memcpy(data, &Buffer[y][0], row_size);
    al_unlock_bitmap(bmp);
    al_flip_display();*/
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////